home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume19 / rkive / part04 < prev    next >
Encoding:
Internet Message Format  |  1989-06-29  |  39.5 KB

  1. Subject:  v19i101:  Usenet sources archiver, Part04/04
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Kent Landfield <ssbell!kent>
  7. Posting-number: Volume 19, Issue 101
  8. Archive-name: rkive/part04
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 4 (of 4)."
  17. # Contents:  news_arc.c rkive.c
  18. # Wrapped by kent@ssbell on Thu Jun  1 16:19:18 1989
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'news_arc.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'news_arc.c'\"
  22. else
  23. echo shar: Extracting \"'news_arc.c'\" \(20172 characters\)
  24. sed "s/^X//" >'news_arc.c' <<'END_OF_FILE'
  25. X/*
  26. X**
  27. X** This software is Copyright (c) 1989 by Kent Landfield.
  28. X**
  29. X** Permission is hereby granted to copy, distribute or otherwise 
  30. X** use any part of this package as long as you do not try to make 
  31. X** money from it or pretend that you wrote it.  This copyright 
  32. X** notice must be maintained in any copy made.
  33. X**
  34. X**
  35. X**  History:
  36. X**    Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
  37. X**                                                               
  38. X*/
  39. X#ifndef lint
  40. Xstatic char SID[] = "@(#)news_arc.c    1.1 6/1/89";
  41. X#endif
  42. X
  43. X#include <sys/types.h>
  44. X#include <sys/stat.h>
  45. X#include <dirent.h>
  46. X#include <stdio.h>
  47. X#include <ctype.h>
  48. X#include "article.h"
  49. X#include "cfg.h"
  50. X
  51. X/*
  52. X** Defines for the type of "problems"
  53. X** encountered in saving the articles.
  54. X*/
  55. X#define DUP_PROB    0
  56. X#define NAME_PROB   1
  57. X#define VOL_PROB    2
  58. X#define TYPE_PROB   3
  59. X
  60. Xint test = 0;
  61. Xint problem_article;
  62. X
  63. Xextern struct group_archive *newsgrp;
  64. Xextern int overwrite;
  65. X
  66. Xchar *strchr();
  67. Xchar *strcpy();
  68. Xchar *strcat();
  69. Xchar *do_problem();
  70. Xchar *basename();
  71. Xchar *suffix();
  72. XFILE *efopen();
  73. Xvoid exit();
  74. X
  75. Xget_header(filename)
  76. X    char *filename;
  77. X{
  78. X    char *dp;
  79. X    int header_ok = 0;
  80. X    FILE *gfp;
  81. X
  82. X    init_article();
  83. X
  84. X    gfp = efopen(filename,"r");
  85. X
  86. X    (void) strcpy(article.newsarticle, filename);
  87. X
  88. X    while (fgets(s,sizeof s,gfp) != NULL) {
  89. X        if (debug)
  90. X            (void) fprintf(logfp, "BUF = [%s]",s);
  91. X
  92. X        if (!isalpha(*s) || (strchr(s,':') == NULL)) {
  93. X           header_ok++;
  94. X           if (header_ok == 2) 
  95. X               break;
  96. X           continue;
  97. X        }
  98. X
  99. X        dp = s;
  100. X        while (*++dp)
  101. X           if (*dp == '\n')
  102. X               *dp = '\0';
  103. X
  104. X        store_line();
  105. X    }
  106. X    (void) fclose(gfp);
  107. X
  108. X    if (debug)
  109. X        dump_article();
  110. X}
  111. X
  112. X/*
  113. X** check_archive_name
  114. X**
  115. X** Assure the path specified is within the base directory
  116. X** specified by the archive administrator by assuring that
  117. X** a prankster could not have an article archived at a
  118. X**     basedir/../../../etc/passwd
  119. X** location.
  120. X**
  121. X** If an absoulte path is specified in the Archive-name, it
  122. X** is of no concern since a "checked" base directory and
  123. X** volume directory are prefixed.
  124. X*/
  125. X
  126. Xcheck_archive_name(argstr)
  127. X    char *argstr;
  128. X {
  129. X    char *substr();
  130. X    register char *rp;
  131. X    register char *dp;
  132. X
  133. X    /* 
  134. X    ** check to assure that the path specified
  135. X    ** does not contain the '..' sequence.
  136. X    */
  137. X
  138. X    while ((rp = substr(argstr, "..")) != NULL) {
  139. X       dp = rp+2;
  140. X       while(*dp)
  141. X           *rp++ = *dp++;
  142. X       *rp = '\0';
  143. X    }
  144. X
  145. X    /* I know this is not necessary but what the heck.. */
  146. X
  147. X    while ((rp = substr(argstr, "//")) != NULL) {
  148. X       dp = rp+2;
  149. X       ++rp;
  150. X       while(*dp)
  151. X           *rp++ = *dp++;
  152. X       *rp = '\0';
  153. X    }
  154. X
  155. X    /* 
  156. X    ** strip the string of trailing '/'s
  157. X    */
  158. X
  159. X    dp = argstr+(strlen(argstr)-1);
  160. X    while(*dp == '/' && dp > argstr)
  161. X        *dp = '\0';
  162. X}
  163. X
  164. X/*
  165. X** IF YOU USE A COMPRESSION ROUTINE OTHER THAN COMPRESS
  166. X** OR PACK, ADD YOUR COMPRESSION SPECIFIC INFORMATION
  167. X** TO THE cprgs COMPRESS_TABLE ......
  168. X*/
  169. X
  170. Xstruct compress_tab {
  171. X    char     *com_name;
  172. X    char     *com_suffix;
  173. X};
  174. X
  175. Xstruct compress_tab cprgs[] = {
  176. X{    "compress",        ".Z"    },
  177. X{    "pack",            ".z"    },
  178. X{    NULL,            0    },
  179. X};
  180. X
  181. Xchar *suffix(compression)
  182. X    char *compression;
  183. X {
  184. X    struct compress_tab *ct;
  185. X
  186. X    ct = &cprgs[0];
  187. X    while ((ct->com_name) != NULL) {
  188. X        if (strcmp(compression, ct->com_name) == 0) 
  189. X            return(ct->com_suffix);
  190. X        ct++;
  191. X    }
  192. X    return("");
  193. X}
  194. X
  195. Xint remove_suffix(path_str)
  196. Xchar *path_str;
  197. X {
  198. X    char *ss;
  199. X    struct compress_tab *ct;
  200. X
  201. X    /*
  202. X    ** need to compare the filename passed in to 
  203. X    ** the compression suffix table in order to
  204. X    ** determine if the file has a recognized,
  205. X    ** compression suffix attached.
  206. X    */
  207. X    
  208. X    ss = path_str + (strlen(path_str) -2);
  209. X
  210. X    ct = &cprgs[0];
  211. X    while ((ct->com_name) != NULL) {
  212. X        if (strcmp(ss, ct->com_suffix) == 0) {
  213. X            *ss = '\0';
  214. X            return(TRUE);
  215. X        }
  216. X        ct++;
  217. X    }
  218. X    return(FALSE);
  219. X}
  220. X
  221. Xchar *expand_name(filename,ng)
  222. Xchar *filename;
  223. Xstruct group_archive *ng;
  224. X{
  225. X    char *comp_cmd;
  226. X    static char compress_path[MAXNAMLEN];
  227. X
  228. X    (void) strcpy(compress_path, filename);
  229. X
  230. X    /*
  231. X    ** Check to see if a group specific compress was specified.      
  232. X    ** If so, then attach the suffix and return.                    
  233. X    ** Else check to see if a global compress was specified. If so,
  234. X    ** then attach the suffix and return.                         
  235. X    ** If both are NULL, return filename.                        
  236. X    */
  237. X
  238. X    if (*(ng->compress)) {
  239. X        comp_cmd = basename(ng->compress);
  240. X        (void) strcat(compress_path, suffix(comp_cmd));
  241. X    }
  242. X    else if (*compress) {
  243. X        comp_cmd = basename(compress);
  244. X        (void) strcat(compress_path, suffix(comp_cmd));
  245. X    }
  246. X    return(compress_path);
  247. X}
  248. X
  249. X#ifdef REDUCE_HEADERS
  250. X
  251. Xstruct hdrstokeep {
  252. X    char     *ststr;
  253. X    int    stbytes;
  254. X};
  255. X
  256. Xstruct hdrstokeep hdrs[] = {
  257. X{    "From:",        (sizeof "From:")    },
  258. X{    "Newsgroups:",        (sizeof "Newsgroups:")    },
  259. X{    "Subject:",        (sizeof "Subject:")    },
  260. X{    "Message-ID:",        (sizeof "Message-ID:")    },
  261. X{    "Date:",        (sizeof "Date:")    },
  262. X{    NULL,            0            },
  263. X};
  264. X
  265. Xint keep_line(argstr)
  266. X    char *argstr;
  267. X {
  268. X    struct hdrstokeep *pt;
  269. X
  270. X    pt = &hdrs[0];
  271. X    while ((pt->ststr) != NULL) {
  272. X        if (strncmp(argstr, pt->ststr, (pt->stbytes-1)) == 0) 
  273. X            return(TRUE);
  274. X        pt++;
  275. X    }
  276. X    return(FALSE);
  277. X}
  278. X
  279. Xint copy(source, target)
  280. X    char *source, *target;
  281. X{
  282. X    char *strchr();
  283. X    FILE *from, *to;
  284. X    char fbuf[BUFSIZ];
  285. X    int inheader;
  286. X
  287. X    inheader = TRUE;  
  288. X
  289. X    if (verbose) {
  290. X        (void) fprintf(logfp,"archive <%s> to <%s>\n",source,target);
  291. X        if (test) 
  292. X            return(0);
  293. X    }
  294. X    if ((from = fopen(source, "r")) == NULL) {
  295. X        (void) fprintf(errfp,"%s: cannot open %s\n",progname,source);
  296. X        return (-1);
  297. X    }
  298. X    if ((to = fopen(target, "w")) == NULL) {
  299. X        (void) fclose(from);
  300. X        (void) fprintf(errfp,"%s: cannot create %s\n",progname,target);
  301. X        return (-1);
  302. X    }
  303. X    /*
  304. X    ** Read the source and do not print any headers 
  305. X    ** unless specified in the "keep" headers table.
  306. X    */
  307. X
  308. X    while (fgets(fbuf, BUFSIZ, from) != NULL) {
  309. X        if (inheader) {
  310. X            /* 
  311. X            ** Have I encountered a line without a line type ? 
  312. X            */
  313. X            if (!isalpha(*fbuf) || (strchr(fbuf,':') == NULL)) 
  314. X                inheader = FALSE;
  315. X
  316. X            else {
  317. X                /*
  318. X                ** Determine the type of the header line and 
  319. X                ** decide if this is a line to be kept or pitched.
  320. X                */
  321. X                if (!keep_line(fbuf))
  322. X                    continue;
  323. X            }
  324. X        }
  325. X        if (fputs(fbuf, to) == EOF) {
  326. X            (void) unlink(target);
  327. X            (void) fclose(from);
  328. X            (void) fclose(to);
  329. X            (void) fprintf(errfp,"%s: bad copy to %s\n",progname,target);
  330. X            return (-1);
  331. X        }
  332. X    }
  333. X    (void) fclose(from);
  334. X    (void) fclose(to);
  335. X    return(0);
  336. X}
  337. X
  338. X#else
  339. X
  340. Xcopy(source, target)
  341. X    char *source, *target;
  342. X{
  343. X    int from, to, ct;
  344. X    char fbuf[BUFSIZ];
  345. X
  346. X    if (verbose) {
  347. X        (void) fprintf(logfp,"archive <%s> to <%s>\n",source,target);
  348. X        if (test) 
  349. X            return(0);
  350. X    }
  351. X    if ((from = open(source, 0)) < 0) {
  352. X        (void) fprintf(errfp,"%s: cannot open %s\n",progname,source);
  353. X        return (-1);
  354. X    }
  355. X    if ((to = creat (target, 0644)) < 0) {
  356. X        (void) close(from);
  357. X        (void) fprintf(errfp,"%s: cannot create %s\n",progname,target);
  358. X        return (-1);
  359. X    }
  360. X    while ((ct = read(from, fbuf, BUFSIZ)) != 0) {
  361. X        if(ct < 0 || write(to, fbuf, (unsigned) ct) != ct) {
  362. X            (void) unlink(target);
  363. X            (void) close(from);
  364. X            (void) close(to);
  365. X            (void) fprintf(errfp,"%s: bad copy to %s\n",progname,target);
  366. X            return (-1);
  367. X        }
  368. X    }
  369. X    (void) close(from);
  370. X    (void) close(to);
  371. X    return(0);
  372. X}
  373. X
  374. X#endif /* REDUCE_HEADERS */
  375. X
  376. X/*
  377. X** mkparents:
  378. X**
  379. X** If any parent directories in 
  380. X** fullname don't exist, create them.
  381. X*/
  382. X
  383. Xint mkparents(fullname)
  384. Xchar *fullname;
  385. X{
  386. X    char *strrchr();
  387. X
  388. X    register char *p;
  389. X    char b[MAXNAMLEN];
  390. X    int rc;
  391. X
  392. X    (void) strcpy(b, fullname);
  393. X
  394. X    if ((p = strrchr(b, '/')) != NULL) 
  395. X            *p = '\0';
  396. X    else                  /* no directories in fullname */
  397. X       return(0);
  398. X
  399. X    if (*b == '\0')           /* are we at the root ? */
  400. X        return(0);
  401. X
  402. X    if (access(b, 0) == 0)
  403. X        return(0);
  404. X
  405. X    (void) mkparents(b);
  406. X
  407. X    if ((rc = makedir(b, 0755, newsgrp->owner, newsgrp->group)) != 0) 
  408. X        error("makedir failed attempting to make", b);
  409. X
  410. X    return(rc);
  411. X}
  412. X
  413. X
  414. Xchar *save_article (filename,ng)
  415. Xchar *filename;
  416. Xstruct group_archive *ng;
  417. X{
  418. X    char *final_path;
  419. X    static char path[MAXNAMLEN];
  420. X    struct stat sb;
  421. X
  422. X    problem_article = FALSE;
  423. X    path[0] = '\0';
  424. X
  425. X    /*
  426. X    ** Read the news article file to extract the
  427. X    ** header information and fill appropriate
  428. X    ** data structures.
  429. X    */
  430. X    get_header(filename);
  431. X
  432. X    /*
  433. X    ** Build the path string for the final resting spot
  434. X    ** for the new archive member.
  435. X    */
  436. X    switch(ng->type) {
  437. X    case ARCHIVE_NAME:
  438. X            /*
  439. X            ** The header's archive_name contains the filename in
  440. X            ** an "elm/part06" format.
  441. X            */
  442. X
  443. X            if ((article.volume == -1) || (!header.archive_name[0])) 
  444. X                return(do_problem(NAME_PROB, ng,filename,path));
  445. X    
  446. X            /*
  447. X            ** Assure the address is relative and
  448. X            ** that some prankster can not do nasty
  449. X            ** things to your system files by having
  450. X            ** an Archive-name line like:
  451. X            **    ../../../../../etc/passwd
  452. X            */
  453. X
  454. X            check_archive_name(header.archive_name);
  455. X
  456. X            /* 
  457. X            ** Check to see if the article is a patch. If so,
  458. X            ** check to see if the administrator wishes to
  459. X            ** store the patch with the initially posted
  460. X            ** articles. This really relys on the archive name
  461. X            ** being correct.
  462. X            */
  463. X            
  464. X            if (article.rectype == PATCH && ng->patch_type == PACKAGE)
  465. X                /*
  466. X                ** Store the patch in the volume specified with the
  467. X                ** Archive-name: specified file name.
  468. X                */
  469. X                (void) sprintf(path,"%s/%s%d/%s", ng->location, VOLUME,
  470. X                    article.patch_volume, header.archive_name);
  471. X
  472. X            else 
  473. X                (void) sprintf(path,"%s/%s%d/%s", ng->location, VOLUME,
  474. X                article.volume, header.archive_name);
  475. X            break;
  476. X    case VOLUME_ISSUE:
  477. X            /*
  478. X            ** The article filename contains the filename in
  479. X            ** a "v01i001" format.
  480. X            */
  481. X            if ((article.volume == -1) || (!article.filename[0])) 
  482. X                return(do_problem(VOL_PROB,ng,filename,path));
  483. X
  484. X            (void) sprintf(path,"%s/%s%d/%s", ng->location, VOLUME,
  485. X                article.volume, article.filename);
  486. X            break;
  487. X    case ARTICLE_NUMBER:
  488. X            /*
  489. X            ** Store in same filename - thanks news...
  490. X            */
  491. X            (void) sprintf(path,"%s/%s", ng->location, filename);
  492. X            break;
  493. X    default:
  494. X            /*
  495. X            ** We have got problems....
  496. X            */
  497. X            return(do_problem(TYPE_PROB,ng,filename,path));
  498. X    }
  499. X
  500. X    /*
  501. X    ** Check if the file is a patch. If so, log
  502. X    ** the patch information into the patch log
  503. X    ** in a *non-configurable* format so that
  504. X    ** applications can be written to access the
  505. X    ** file's "known format".
  506. X    */
  507. X
  508. X    if (article.rectype == PATCH)
  509. X        write_patch_log(ng,path);
  510. X
  511. X#ifdef ADD_REPOST_SUFFIX
  512. X    if (article.repost == TRUE)
  513. X        /*
  514. X        ** The ADD_REPOST_SUFFIX code adds the REPOST_SUFFIX
  515. X    ** to any file that has been indicated as a repost
  516. X    ** by the moderator. This should not be used with 
  517. X    ** Archive-Name archiving on a filesystem with 14
  518. X    ** character filename limits or filename truncation
  519. X    ** can occur. You have been warned... :-(
  520. X    **
  521. X     ** After adding the REPOST_SUFFIX, the filename is
  522. X    ** treated as any other file with the duplication
  523. X    ** checks and all...
  524. X    */
  525. X    (void) strcat(path,REPOST_SUFFIX);
  526. X#endif /* ADD_REPOST_SUFFIX */
  527. X
  528. X    /* 
  529. X    ** expand the path to the file to include the 
  530. X    ** compression suffix if necessary.
  531. X    */
  532. X
  533. X    final_path = expand_name(path, ng);
  534. X
  535. X    /*
  536. X    ** Make any necessary directories 
  537. X    ** along the way. 
  538. X    */
  539. X    (void) mkparents(path);
  540. X
  541. X    /*
  542. X    ** Check to assure that there is not already 
  543. X    ** a file with the same file name. If so
  544. X    ** copy (or archive) the file to the problems 
  545. X    ** directory. 
  546. X    **
  547. X    ** This works for REPOSTS as well.
  548. X    ** If the REPOST arrives and there is
  549. X    ** no file currently at the archive location, the
  550. X    ** REPOST is installed in the correct archive 
  551. X    ** location.
  552. X    ** If there is a file that exists when a REPOST
  553. X    ** arrives, the REPOST is then handled in do_problem().
  554. X    */
  555. X
  556. X    if ((stat(final_path ,&sb) == 0) && !overwrite)  /* duplicate found */
  557. X        return(do_problem(DUP_PROB,ng, filename, final_path));
  558. X
  559. X    if (copy(filename,path) != 0) {  
  560. X        (void) fprintf(errfp,"copy failed for %s to %s\n",filename,path);
  561. X        return(NULL);
  562. X    }  
  563. X    /* 
  564. X    ** Write the filename to the .archived file in the newsgroup's
  565. X    ** BASEDIR directory since we do not want it rearchived tomorrow.
  566. X    */
  567. X    write_archived(filename, path);
  568. X
  569. X    /*
  570. X    ** Return the path to the archived file.
  571. X    */
  572. X    return(path);
  573. X}
  574. X
  575. X
  576. X
  577. Xchar *do_problem(type_of_problem, ng, file, path)
  578. Xint type_of_problem;
  579. Xstruct group_archive *ng;
  580. Xchar *file;
  581. Xchar *path;
  582. X{
  583. X
  584. X#ifdef MV_ORIGINAL
  585. X    char crnt_path[MAXNAMLEN];
  586. X#endif /*MV_ORIGINAL */
  587. X
  588. X    char pmess[BUFSIZ];
  589. X
  590. X    problem_article = TRUE;
  591. X
  592. X    /* ALERT THE ADMINISTRATOR THAT A PROBLEM WAS ENCOUNTERED 
  593. X    **
  594. X    ** A problem has been encountered. It could be that there is an
  595. X    ** format mismatch or there is already a file with the same 
  596. X    ** issue/archive/msg-id name.
  597. X    ** Copy the problem file to the problems directory. 
  598. X    ** Alert the Administrator that a problem was received.
  599. X    */
  600. X
  601. X    (void) sprintf(pmess,"PROBLEM: Article %s in %s ",file,ng->ng_name);
  602. X
  603. X    switch( type_of_problem ) {
  604. X       case NAME_PROB:
  605. X          (void) strcat(pmess,"does not support Archive-Name Archiving\n.");
  606. X          break;
  607. X       case VOL_PROB:
  608. X          (void) strcat(pmess,"does not support Volume-Issue Archiving\n.");
  609. X          break;
  610. X       case TYPE_PROB:
  611. X          (void) strcat(pmess,"has an invalid archive TYPE specified\n.");
  612. X          break;
  613. X       case DUP_PROB:
  614. X          if (article.repost != TRUE) 
  615. X              (void) strcat(pmess,"is a Duplicate article.\n");
  616. X          else 
  617. X             (void) strcat(pmess,"is a Reposted article.\n");
  618. X          (void) sprintf(pmess,"%s\tExisting Archived path - %s", pmess,path);
  619. X          break;
  620. X    }
  621. X
  622. X    /* print the message out to the screen, crontab output, etc */
  623. X
  624. X    (void) fprintf(errfp,"%s\n",pmess);
  625. X
  626. X    /* log the initial detection message. */
  627. X
  628. X    record_problem(pmess, file, ng);
  629. X
  630. X    /* Handling Repostings.
  631. X    **
  632. X    ** MV_ORIGINAL
  633. X    **     The original article is placed into a "original" directory in 
  634. X    **     the problems directory (if duplicated). The inbound reposted
  635. X    **     article is placed into the archive in the correct position.
  636. X    **
  637. X    ** ADD_REPOST_SUFFIX 
  638. X    **     If ADD_REPOST_SUFFIX is defined, all reposts will have the 
  639. X    **     string specified in REPOST_SUFFIX appended to the archive
  640. X    **     filename so that a repost of elm/part07 would appear in
  641. X    **     the archive as elm/part07-repost prior to any compression.
  642. X    **     The addition of the suffix was done in save_article().
  643. X    **     Handle this as the true duplicated article that it is.
  644. X    **
  645. X    ** No Reposting Defines specified:
  646. X    **    The inbound article would be placed into the archive in the 
  647. X    **    correct position only if the initial article is not in the archive.
  648. X    **    Otherwise the reposted article is placed in the problems directory 
  649. X    **    as a normal duplicate article as it is now.
  650. X    */
  651. X
  652. X#ifdef MV_ORIGINAL
  653. X    if (article.repost == TRUE) {
  654. X        /*
  655. X        ** save the duplicated path 
  656. X        ** Caution: may have compression suffix attached
  657. X        */
  658. X        (void) strcpy(crnt_path, path);
  659. X
  660. X        /* create the storage path for original copy */
  661. X        /* no slash needed between Originals and crnt_path below.. */
  662. X
  663. X        (void) sprintf(path,"%s/%s%s",problems_dir,"Originals",crnt_path);
  664. X
  665. X        /* Display and record the actions */ 
  666. X        (void) sprintf(pmess,"\tMoving %s (original)\n\tto %s",crnt_path,path);
  667. X        (void) fprintf(errfp,"%s\n",pmess);
  668. X        record_problem(pmess, file, ng);
  669. X
  670. X        /* Make any necessary directories along the way. */
  671. X        (void) mkparents(path);
  672. X
  673. X        /* copy the original out of the way */
  674. X        if (copy(crnt_path,path) != 0) {
  675. X            (void) fprintf(errfp,"copy failed for %s to %s\n", crnt_path, path);
  676. X            return(NULL);
  677. X        }
  678. X
  679. X        set_ownership(path, ng);
  680. X
  681. X        /* restore the destination path for inbound article */
  682. X        (void) strcpy(path,crnt_path);
  683. X
  684. X        /* remove the existing file */
  685. X        (void) unlink(path);
  686. X        /*
  687. X        ** Must assure that "path" does not have a .Z type
  688. X        ** of suffix used in compression. If it does, it must 
  689. X    ** be removed before continuing. This is cheating and
  690. X        ** will probably break but what the hell.
  691. X        */
  692. X        (void) remove_suffix(path);
  693. X    }
  694. X    else 
  695. X
  696. X#endif /* MV_ORIGINAL */
  697. X
  698. X    /*
  699. X    ** Build the path string for the location of the article in 
  700. X    ** the problems directory. Place the file in the appropriate 
  701. X    ** directory in Article-Number format. In this manner, multiple 
  702. X    ** problems will be stored as separate files. 
  703. X    */
  704. X
  705. X        (void) sprintf(path,"%s/%s/%s",problems_dir,ng->ng_name,file);
  706. X
  707. X    /* Display and record the actions */ 
  708. X    (void) sprintf(pmess,"\tStoring Article %s at %s\n", file, path);
  709. X    (void) fprintf(errfp,"%s\n",pmess);
  710. X    record_problem(pmess, file, ng);
  711. X
  712. X    /* Make any necessary directories along the way. */
  713. X    (void) mkparents(path);
  714. X
  715. X    if (copy(file,path) != 0) {  
  716. X        (void) fprintf(errfp,"copy failed for %s to %s\n", file, path);
  717. X        return(NULL);
  718. X    }  
  719. X
  720. X    /* 
  721. X    ** Write the filename to the .archived file in the newsgroup's
  722. X    ** BASEDIR directory since we do not want it rearchived tomorrow.
  723. X    */
  724. X    write_archived(file, path);
  725. X
  726. X    /*
  727. X    ** Return the path to the stored problem file.
  728. X    */
  729. X    return(path);
  730. X}
  731. X
  732. Xwrite_patch_log(ng, path)
  733. X    struct group_archive *ng;
  734. X    char *path;
  735. X{
  736. X        char *sp;
  737. X    FILE *plfp;
  738. X    struct stat sb;
  739. X        int hn;
  740. X
  741. X    /* 
  742. X    ** The .patchlog file is used to record the
  743. X    ** information specific to patches that come
  744. X    ** through the newsgroup.
  745. X    **
  746. X    ** The format of the .patchlog file is:
  747. X    **
  748. X    ** path-to-patch  initial-volume  initial-issue  volume issue 
  749. X    ** bb/patch01          22              105         23    77
  750. X    ** v47i022             22              105         23    77
  751. X    */
  752. X
  753. X        /*
  754. X        ** If this is the first time that an entry is written to the
  755. X        ** patch log, add a header on top of the file for informational
  756. X        ** purposes only...
  757. X        */
  758. X    if ((stat(ng->patchlog ,&sb) != 0)) {
  759. X        plfp = efopen(ng->patchlog,"a+");
  760. X
  761. X        (void) fprintf(plfp,"#\n#\tPatch log for %s\n#\n",
  762. X                    ng->ng_name);
  763. X
  764. X        (void) fprintf(plfp,"# %-30s%-11s%-13s%-6s%10s\n", 
  765. X                    "Path To", "Initial", "Initial",
  766. X                    "Current", "Current");
  767. X
  768. X        (void) fprintf(plfp,"# %-30s%-11s%6s%13s%10s\n#\n", 
  769. X                    "Patchfile", "Volume", "Issue", "Volume", "Issue");
  770. X        (void) fclose(plfp);
  771. X        }
  772. X
  773. X        /* 
  774. X        ** Get rid of the base directory.
  775. X        */
  776. X        sp = path + (strlen(ng->location)+1);
  777. X
  778. X    plfp = efopen(ng->patchlog,"a+");
  779. X    (void) fprintf(plfp,"%-24s%12d%12d%12d%11d\n", sp,
  780. X            article.patch_volume, article.patch_issue,
  781. X            article.volume, article.issue);
  782. X    (void) fclose(plfp);
  783. X}
  784. END_OF_FILE
  785. if test 20172 -ne `wc -c <'news_arc.c'`; then
  786.     echo shar: \"'news_arc.c'\" unpacked with wrong size!
  787. fi
  788. # end of 'news_arc.c'
  789. fi
  790. if test -f 'rkive.c' -a "${1}" != "-c" ; then 
  791.   echo shar: Will not clobber existing file \"'rkive.c'\"
  792. else
  793. echo shar: Extracting \"'rkive.c'\" \(17099 characters\)
  794. sed "s/^X//" >'rkive.c' <<'END_OF_FILE'
  795. X/*
  796. X**                                                                
  797. X**  Subsystem:   USENET Sources Archiver             
  798. X**  File Name:   rkive.c               
  799. X**                                                        
  800. X**  usage: rkive [ -dgstuvV ] [ -f config_file ] [-n newsgroup ]
  801. X**
  802. X**
  803. X** This software is Copyright (c) 1989 by Kent Landfield.
  804. X**
  805. X** Permission is hereby granted to copy, distribute or otherwise 
  806. X** use any part of this package as long as you do not try to make 
  807. X** money from it or pretend that you wrote it.  This copyright 
  808. X** notice must be maintained in any copy made.
  809. X**
  810. X** Use of this software constitutes acceptance for use in an AS IS 
  811. X** condition. There are NO warranties with regard to this software.  
  812. X** In no event shall the author be liable for any damages whatsoever 
  813. X** arising out of or in connection with the use or performance of this 
  814. X** software.  Any use of this software is at the user's own risk.
  815. X**
  816. X**  If you make modifications to this software that you feel 
  817. X**  increases it usefulness for the rest of the community, please 
  818. X**  email the changes, enhancements, bug fixes as well as any and 
  819. X**  all ideas to me. This software is going to be maintained and 
  820. X**  enhanced as deemed necessary by the community.
  821. X**
  822. X**              Kent Landfield
  823. X**              uunet!ssbell!kent
  824. X**
  825. X**  History:
  826. X**    Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
  827. X**                                                               
  828. X*/
  829. Xchar sccsid[] = "@(#)rkive.c    1.1 6/1/89";
  830. X
  831. X#include <sys/types.h>
  832. X#include <sys/stat.h>
  833. X#include <dirent.h>
  834. X#include <stdio.h>
  835. X#include "article.h"
  836. X#include "cfg.h"
  837. X
  838. X/* 
  839. X** This is necessary since the builtin makedir call uses
  840. X** mknod which is a superuser only call for directories.
  841. X*/
  842. X#if (!HAVE_MKDIR && !USE_SYSMKDIR)
  843. X#define ROOT_ONLY
  844. X#endif
  845. X
  846. X#define UFMT "usage: %s [ -dgstuvV ] [ -f config_file ] [ -n newsgroup ]\n"
  847. X
  848. Xint overwrite;
  849. Xint status_only;
  850. Xstruct stat sbuf;
  851. Xstruct group_archive *newsgrp;
  852. X
  853. Xchar tmp_mailfile[] = "/tmp/rkive.mail";
  854. Xchar global_mailfile[] = "/tmp/gbl.mail";
  855. X
  856. Xchar *save_article();
  857. Xchar *compress_file();
  858. Xchar *do_compress();
  859. Xchar *basename();
  860. Xchar *suffix();
  861. Xvoid archive();
  862. X
  863. Xchar *strcpy();
  864. Xchar *strcat();
  865. Xchar *strchr();
  866. XFILE *efopen();
  867. Xvoid exit();
  868. X
  869. Xextern int debug;
  870. Xextern int verbose;
  871. Xextern int test;
  872. Xextern int problem_article;
  873. X
  874. Xmain(argc, argv)
  875. Xint argc;
  876. Xchar **argv;
  877. X{
  878. X   int c;
  879. X   extern char *optarg;
  880. X   char *nwsg = NULL;
  881. X
  882. X   progname = argv[0];
  883. X   errfp = stderr;
  884. X   logfp = stdout;
  885. X
  886. X   status_only = debug = verbose = 0;
  887. X   test = overwrite = fill_in_defaults = 0;
  888. X
  889. X   /*
  890. X   ** Setup the default config file to be used
  891. X   ** unless the user specifies otherwise.
  892. X   */
  893. X   config_file = LOCATION;
  894. X
  895. X   if (argc > 1) {
  896. X      while ((c = getopt(argc, argv, "dgstuvVn:f:")) != EOF) {
  897. X         switch (c) {
  898. X             case 'f':
  899. X                 config_file = optarg;  
  900. X                 break;  
  901. X             case 'd':
  902. X                 debug++;
  903. X                 verbose++;
  904. X                 break;
  905. X             case 'g':
  906. X                 fill_in_defaults++;
  907. X                 break;
  908. X             case 'n':
  909. X                 nwsg = optarg;
  910. X                 break;
  911. X             case 's':
  912. X                 status_only++;
  913. X                 break;
  914. X             case 't':
  915. X                 test++;
  916. X                 verbose++;
  917. X                 break;
  918. X             case 'u':
  919. X                 overwrite++;
  920. X                 break;
  921. X             case 'v':
  922. X                 verbose++;
  923. X                 break;
  924. X             case 'V':
  925. X                 version();
  926. X             default:
  927. X                 (void) fprintf(errfp, UFMT, progname);
  928. X                 return(1);
  929. X         }
  930. X      }
  931. X   }
  932. X
  933. X   setup_defaults();
  934. X
  935. X   init_article();
  936. X
  937. X   for (c = 0; c <= num; c++)  {
  938. X       newsgrp = &group[c];
  939. X       /*
  940. X       ** Was a newsgroup specified on the command line ?
  941. X       */
  942. X       if (nwsg != NULL) {
  943. X          if (strcmp(nwsg, newsgrp->ng_name) != 0)
  944. X              continue;
  945. X       }
  946. X       archive();
  947. X   }
  948. X
  949. X   if (!status_only) {
  950. X       /*
  951. X       ** Mail notification of the archived members to the 
  952. X       ** list of users specified in the configuration file
  953. X       ** and remove the file containing the archived info.
  954. X       */
  955. X       mail_file(mail, global_mailfile, "Complete Archive Results ");
  956. X       (void) unlink(global_mailfile);
  957. X   }
  958. X   return(0);
  959. X}
  960. X
  961. Xvoid archive()
  962. X{
  963. X    struct dirent *dp;
  964. X    int cct;
  965. X    DIR *dfd;
  966. X    char *rp, *rec;
  967. X    char *dir = ".";
  968. X    char *new_member;
  969. X    char *archived_file;
  970. X    char *get_archived_rec();
  971. X    char newsgroup_directory[MAXNAMLEN];
  972. X    
  973. X#ifdef ROOT_ONLY
  974. X    /*
  975. X    ** check to assure that the user is root if 
  976. X    ** actual archiving is to take place. This is necessary
  977. X    ** if there is no mkdir system call.
  978. X    */
  979. X
  980. X    if (!status_only && (getuid() != 0)) {
  981. X        (void) fprintf(errfp, "%s: Sorry, Must be root to rkive.\n",
  982. X                        progname);
  983. X        exit(1);
  984. X    }
  985. X#endif
  986. X
  987. X    /* Remove any existing temporary mail file */
  988. X
  989. X    (void) unlink(tmp_mailfile);
  990. X    cct = 0;  /* counter for newsgroup message in global mail */
  991. X
  992. X    /*
  993. X    ** Assure that there something specified in the 
  994. X    ** archive location variable...
  995. X    */
  996. X    if (!*newsgrp->location) {
  997. X        (void) fprintf(errfp, "SKIPPING %s: No archive location specified..\n",
  998. X                        newsgrp->ng_name);
  999. X        return;
  1000. X    }
  1001. X
  1002. X    /*
  1003. X    ** print out the appropriate 
  1004. X    ** header for the newsgroup.
  1005. X    */
  1006. X
  1007. X    if (debug || (verbose && status_only)) {
  1008. X        (void) fprintf(logfp,"\n\n");
  1009. X        display_group_info(newsgrp);
  1010. X        (void) fprintf(logfp,"\n");
  1011. X    }
  1012. X    else if (status_only)
  1013. X        (void) fprintf(logfp, "%s\n",newsgrp->ng_name);
  1014. X
  1015. X    /* convert newsgroup name into a disk path */
  1016. X
  1017. X    rp = newsgrp->ng_name;
  1018. X
  1019. X    /*
  1020. X    ** convert all '.' to '/' to generate a path to the
  1021. X    ** newsgroup directory relative from the specified SPOOLDIR.
  1022. X    */
  1023. X
  1024. X    while (*rp) {             /* convert all */
  1025. X        if (*rp == '.')       /* '.'s to '/' */
  1026. X            *rp = '/';        /* to create   */
  1027. X        rp++;                 /* the disk    */
  1028. X    }                         /* location    */
  1029. X
  1030. X    (void) sprintf(newsgroup_directory,"%s/%s", spooldir,newsgrp->ng_name);
  1031. X
  1032. X    if (chdir(newsgroup_directory) != 0) {
  1033. X       (void) fprintf(errfp,"Can't change directory to %s, %s not archived\n",
  1034. X                     newsgroup_directory, newsgrp->ng_name);
  1035. X       return;
  1036. X    }
  1037. X
  1038. X    /*
  1039. X    ** Create a path to the .archived file for the newsgroup's archive.
  1040. X    ** This file is used to determine if an article has already been
  1041. X    ** archived.
  1042. X    */
  1043. X    (void) sprintf(newsgrp->arc_done,"%s/.archived",newsgrp->location);
  1044. X
  1045. X    /*
  1046. X    ** Create a path to the .patchlog file for the newsgroup's archive.
  1047. X    ** This file is used to record patches to posted software so that
  1048. X    ** it can easily be determined what the full set of software is.
  1049. X    */
  1050. X    (void) sprintf(newsgrp->patchlog,"%s/.patchlog",newsgrp->location);
  1051. X
  1052. X    /*
  1053. X    ** locate a file that needs to be archived. This is done by
  1054. X    ** a linear search of the directory with a linear search of
  1055. X    ** of the contents of the .archived file. If the file is not
  1056. X    ** specified in the .archived file, it has not been archived
  1057. X    ** before and we can proceed with the archiving.
  1058. X    */
  1059. X    if ((dfd  = opendir(dir)) == NULL) {
  1060. X        (void) fprintf(errfp, "can't open %s\n", newsgroup_directory);
  1061. X        return;
  1062. X    }
  1063. X    while ((dp = readdir(dfd)) != NULL) {
  1064. X       if (strcmp(dp->d_name,".") == 0
  1065. X           || strcmp(dp->d_name,"..") == 0)
  1066. X           continue;
  1067. X
  1068. X       if (stat(dp->d_name, &sbuf) != 0)  {
  1069. X           (void) fprintf(errfp, "can't stat %s/%s\n",
  1070. X                          newsgroup_directory, dp->d_name);
  1071. X           continue;
  1072. X       }
  1073. X
  1074. X       /* 
  1075. X       ** If its not a regular file, we cannot archive it. 
  1076. X       */
  1077. X
  1078. X       else if ((sbuf.st_mode & S_IFMT) != S_IFREG) 
  1079. X           continue; 
  1080. X        
  1081. X       /* 
  1082. X       ** If the user has specified that a quick status 
  1083. X       ** listing should be produced then hop to it....
  1084. X       */
  1085. X
  1086. X       if (status_only) {
  1087. X            if ((rec = get_archived_rec(dp->d_name)) == NULL) 
  1088. X                (void) fprintf(logfp,"\t<%s> Awaiting Archiving\n",dp->d_name);
  1089. X            else if ((rp = strchr(rec,' ')) == NULL)
  1090. X                (void) fprintf(logfp,"\t<%s> Archived\n",dp->d_name);
  1091. X            else {
  1092. X                rp++;
  1093. X                *(rp-1) = '\0';
  1094. X                (void) fprintf(logfp,"\t<%s> Archived as <%s>\n",rec,rp);
  1095. X            }
  1096. X            continue;
  1097. X       }
  1098. X
  1099. X       /* 
  1100. X       ** Archiving from here on out.
  1101. X       */
  1102. X
  1103. X       if (!needs_to_be_archived(dp->d_name)) 
  1104. X           continue;
  1105. X           
  1106. X       if ((new_member = save_article(dp->d_name,newsgrp)) != NULL) {
  1107. X           archived_file = compress_file(new_member,newsgrp);
  1108. X           set_ownership(archived_file,newsgrp);
  1109. X           
  1110. X           /*
  1111. X           ** If a problem has been encountered,
  1112. X           ** the function do_problem handles
  1113. X           ** the logging, and notifying.
  1114. X           */
  1115. X
  1116. X           if (!problem_article) {
  1117. X               log_activities(archived_file,newsgrp);
  1118. X               build_index(new_member,newsgrp);
  1119. X               notify_users(archived_file,newsgrp,cct++);
  1120. X           }
  1121. X       }
  1122. X       else 
  1123. X           (void) fprintf(logfp,"Unable to archive %s/%s!!!\n",
  1124. X                          newsgrp->ng_name, dp->d_name);
  1125. X    }
  1126. X    (void) closedir(dfd);
  1127. X
  1128. X    if (!status_only) {
  1129. X        /* Remove the expired entries from the .archived file */
  1130. X        /* stored in the newsgroup's BASEDIR directory.       */
  1131. X
  1132. X        remove_expired();
  1133. X
  1134. X        /* Mail notification of the archived members to the   */
  1135. X        /* list of users specified in the configuration file  */
  1136. X        /* and remove the file containing the archived info.  */
  1137. X
  1138. X        mail_file(newsgrp->mail_list, tmp_mailfile, newsgrp->ng_name);
  1139. X        (void) unlink(tmp_mailfile);
  1140. X    }
  1141. X    return;
  1142. X}
  1143. X
  1144. X/* 
  1145. X** Notify Users of Archiving.
  1146. X**      If users have been specified to be informed, check to see
  1147. X**      if they have requested a specific logging format. If so
  1148. X**      use the specified format to notify the user. If not, use
  1149. X**      "file archived at path" message.
  1150. X*/
  1151. Xnotify_users(filename,ng,num_msgs)
  1152. Xchar *filename;
  1153. Xstruct group_archive *ng;
  1154. Xint num_msgs;
  1155. X{
  1156. X    /*
  1157. X    ** Are there users specified in the 
  1158. X    ** newsgroup section ? 
  1159. X    */
  1160. X    if ( *(ng->mail_list) ) {
  1161. X        if ( *(ng->logformat) )
  1162. X           logit(tmp_mailfile, ng->logformat, filename);
  1163. X        else
  1164. X           logit(tmp_mailfile, DEFAULT_LOG_FORMAT, filename);
  1165. X    }
  1166. X
  1167. X    /* 
  1168. X    ** Are there users specified in the 
  1169. X    ** global section ? 
  1170. X    */
  1171. X    if ( *mail ) {
  1172. X        if (num_msgs == 0) /* print the newsgroup name out */
  1173. X            logit(global_mailfile, "\n\t\t:%G:\n",filename);
  1174. X        if (*log_format)
  1175. X            logit(global_mailfile, log_format,filename);
  1176. X        else 
  1177. X            logit(global_mailfile, DEFAULT_LOG_FORMAT, filename);
  1178. X    }
  1179. X}
  1180. X
  1181. X/*
  1182. X** Log_activities
  1183. X**
  1184. X** There are two possible logfiles that need to be written. 
  1185. X** The group specific logfile (ng->logfile) and the global 
  1186. X** log. If it has been configured to use a specific format
  1187. X** for the logging, do so. Else, just record the fact the
  1188. X** file was sucessfully archived and the date.          
  1189. X*/
  1190. Xlog_activities(filename,ng)
  1191. Xchar *filename;
  1192. Xstruct group_archive *ng;
  1193. X{
  1194. X   long clock;
  1195. X   long time();
  1196. X   char *ctime();
  1197. X   
  1198. X   char logbuf[BUFSIZ];
  1199. X   char dms_date[30];
  1200. X   
  1201. X   if ( !*(ng->logformat) || !*log_format) {
  1202. X       clock = time((long *)0);
  1203. X       (void) strcpy(dms_date, ctime(&clock));
  1204. X       *(dms_date+(strlen(dms_date)-1)) = '\0';
  1205. X       (void) sprintf(logbuf,"%s archived %s",filename, dms_date);
  1206. X   }
  1207. X
  1208. X   if ( *(ng->logformat) )
  1209. X       logit(ng->logfile, ng->logformat, filename);
  1210. X   else
  1211. X       logit(ng->logfile, logbuf, filename);
  1212. X
  1213. X   if ( *log_format )
  1214. X       logit(log, log_format, filename);
  1215. X   else
  1216. X       logit(log, logbuf, filename);
  1217. X}
  1218. X
  1219. X/*
  1220. X** logit
  1221. X**
  1222. X** This function is used to append a logfile record 
  1223. X** if there is a logfile name specified.
  1224. X**
  1225. X*/
  1226. X
  1227. Xlogit(filename, format_of_log, arch_file)
  1228. Xchar *filename;
  1229. Xchar *format_of_log;
  1230. Xchar *arch_file;
  1231. X{
  1232. X    FILE *fp, *fopen();
  1233. X
  1234. X    if ( *(filename) ) {   /* Is a logfile specified ? */
  1235. X        if ((fp = fopen(filename,"a")) != NULL) {
  1236. X            format_output(fp, format_of_log, arch_file, ARCHIVE);
  1237. X            (void) fclose(fp);
  1238. X        }
  1239. X    }
  1240. X}    
  1241. X
  1242. X
  1243. Xset_ownership(filename,ng)
  1244. Xchar *filename;
  1245. Xstruct group_archive *ng;
  1246. X{
  1247. X    if (verbose) {  /* Print out the actions about to be preformed */
  1248. X        (void) fprintf(logfp,"chown\t<%d> <%s>\n", ng->owner, filename);
  1249. X        (void) fprintf(logfp,"chgrp\t<%d> <%s>\n", ng->group, filename);
  1250. X    }
  1251. X
  1252. X    if (!test) {    /* chown the owner/group to the desired values */
  1253. X        if (chown(filename,ng->owner, ng->group) != 0)
  1254. X            error("Can't change ownership of", filename);
  1255. X    }
  1256. X
  1257. X    if (verbose) {  /* Print out the actions about to be preformed */
  1258. X        (void) fprintf(logfp,"chmod\t<%o> <%s>\n", ng->modes, filename);
  1259. X    }
  1260. X
  1261. X    if (!test) {    /* change the file modes to the specified modes */
  1262. X        if (chmod(filename,ng->modes) != 0)
  1263. X            error("Can't change modes of", filename);
  1264. X    }
  1265. X}
  1266. X
  1267. Xmail_file(user_list, file_to_mail, nwsgrp)
  1268. Xchar *user_list;
  1269. Xchar *file_to_mail;
  1270. Xchar *nwsgrp;
  1271. X{
  1272. X    char  *list, *name;
  1273. X    char  cmdstr[80];
  1274. X
  1275. X    /* Is there a list of users to mail to ? */
  1276. X    if ( !*user_list || (strlen(user_list) == 0))
  1277. X        return;
  1278. X
  1279. X    /* Was there a notification file created ? */
  1280. X    if (stat(file_to_mail, &sbuf) != 0) 
  1281. X        return;
  1282. X
  1283. X    name = user_list;
  1284. X    do {
  1285. X       if ((list = strchr(name,',')) != NULL) {
  1286. X            list++;
  1287. X            *(list-1) = '\0';
  1288. X        }
  1289. X
  1290. X#ifdef SUBJECT_LINE
  1291. X        (void) sprintf(cmdstr, "%s -s '%s' %s < %s", 
  1292. X                   MAIL, nwsgrp, name, file_to_mail);
  1293. X#else
  1294. X        (void) sprintf(cmdstr, "%s %s < %s", MAIL, name, file_to_mail);
  1295. X#endif
  1296. X        if (verbose)
  1297. X            (void) fprintf(logfp,"Mailing %s Archived results to %s\n",
  1298. X                           nwsgrp, name);
  1299. X        if (!test) 
  1300. X            (void) system(cmdstr);
  1301. X
  1302. X        name = list;
  1303. X
  1304. X    } while (name != NULL);
  1305. X    return;
  1306. X}
  1307. X
  1308. Xbuild_index(filename,ng)
  1309. Xchar *filename;
  1310. Xstruct group_archive *ng;
  1311. X{
  1312. X    if (*(ng->index)) {        /* Is there a newsgroup index file ?  */
  1313. X        if (*(ng->indformat))  /* Yes, Is there a index file format? */
  1314. X            logit(ng->index, ng->indformat, filename);
  1315. X        else if (*index_format)    /* No, is there a global format ? */
  1316. X            logit(ng->index, index_format, filename);
  1317. X        else                   /* No, use the default index format   */
  1318. X            logit(ng->index, DEFAULT_INDEX_FORMAT, filename);
  1319. X    }
  1320. X
  1321. X    if (*index) {            /* Is there a global index file ?       */
  1322. X        if (*index_format)   /* Yes, Is there a global file format ? */
  1323. X            logit(index, index_format, filename);
  1324. X        else                 /* No, so use the default index format  */
  1325. X            logit(ng->index, DEFAULT_INDEX_FORMAT , filename);
  1326. X    }
  1327. X}
  1328. X
  1329. X
  1330. Xchar *compress_file(filename,ng)
  1331. Xchar *filename;
  1332. Xstruct group_archive *ng;
  1333. X{
  1334. X    static char compressed[MAXNAMLEN];
  1335. X
  1336. X    (void) strcpy(compressed, filename);  /* store the filename */
  1337. X
  1338. X    /* Check to see if a group specific compress was specified.      */
  1339. X    /* If so, then execute the command with the filename passed in.  */
  1340. X    /* Else check to see if a global compress was specified. If so,  */
  1341. X    /* then execute the command with the filename passed in.         */
  1342. X    /* If both are NULL, no compression is done.                     */
  1343. X
  1344. X    if (*(ng->compress)) 
  1345. X        (void) strcat(compressed, do_compress(ng->compress, filename));
  1346. X    else if (*compress) 
  1347. X        (void) strcat(compressed, do_compress(compress, filename));
  1348. X
  1349. X    return(compressed);
  1350. X}
  1351. X
  1352. Xchar *do_compress(packit,filename)
  1353. Xchar *packit;
  1354. Xchar *filename;
  1355. X{
  1356. X    char *comp_cmd;
  1357. X    char cmd[BUFSIZ];
  1358. X
  1359. X    (void) sprintf(cmd,"%s %s", packit, filename);
  1360. X
  1361. X    /* 
  1362. X    ** get the basename of the command to use.
  1363. X    */
  1364. X    comp_cmd = basename(packit);
  1365. X
  1366. X    if (verbose)
  1367. X       (void) fprintf(logfp,"%s %s\n", comp_cmd, filename);
  1368. X
  1369. X    if (!test) 
  1370. X       (void) system(cmd);
  1371. X
  1372. X    return(suffix(comp_cmd));
  1373. X}
  1374. X
  1375. X
  1376. X/*
  1377. X** Record_problem()
  1378. X**    This function is used to log problems encountered
  1379. X**    to the designated parties.
  1380. X*/
  1381. Xrecord_problem(msg_fmt,filename,ng)
  1382. Xchar *msg_fmt;
  1383. Xchar *filename;
  1384. Xstruct group_archive *ng;
  1385. X{
  1386. X    /* 
  1387. X    ** This function is used in the event that a problem
  1388. X    ** has occurred during archiving. It mails a message
  1389. X    ** to the newsgroup speecified list and it mails a 
  1390. X    ** message to the globally specified users.
  1391. X    ** 
  1392. X    ** It then logs the fact into both the newsgroup 
  1393. X    ** and the global logfiles if they have been specified.
  1394. X    */
  1395. X
  1396. X    if ( *(ng->mail_list) ) 
  1397. X        logit(tmp_mailfile, msg_fmt, filename);
  1398. X    
  1399. X    if ( *mail ) 
  1400. X        logit(global_mailfile, msg_fmt,filename);
  1401. X    
  1402. X    logit(ng->logfile, msg_fmt, filename);
  1403. X    logit(log, msg_fmt, filename);
  1404. X}
  1405. END_OF_FILE
  1406. if test 17099 -ne `wc -c <'rkive.c'`; then
  1407.     echo shar: \"'rkive.c'\" unpacked with wrong size!
  1408. fi
  1409. # end of 'rkive.c'
  1410. fi
  1411. echo shar: End of archive 4 \(of 4\).
  1412. cp /dev/null ark4isdone
  1413. MISSING=""
  1414. for I in 1 2 3 4 ; do
  1415.     if test ! -f ark${I}isdone ; then
  1416.     MISSING="${MISSING} ${I}"
  1417.     fi
  1418. done
  1419. if test "${MISSING}" = "" ; then
  1420.     echo You have unpacked all 4 archives.
  1421.     rm -f ark[1-9]isdone
  1422. else
  1423.     echo You still need to unpack the following archives:
  1424.     echo "        " ${MISSING}
  1425. fi
  1426. ##  End of shell archive.
  1427. exit 0
  1428.  
  1429.